package com.xc.file.web.rest;

import com.xc.core.annotation.Authority;
import com.xc.core.dto.AppDto;
import com.xc.core.enums.RedisTime;
import com.xc.core.exception.OperateException;
import com.xc.core.exception.ResultException;
import com.xc.core.model.TokenModel;
import com.xc.core.utils.RedisUtils;
import com.xc.file.bean.UploadBean;
import com.xc.file.config.Constants;
import com.xc.file.dto.SignDto;
import com.xc.file.dto.UploadDto;
import com.xc.file.enums.FailCode;
import com.xc.file.service.FolderService;
import com.xc.file.service.UploadService;
import com.xc.tool.http.HttpResult;
import com.xc.tool.utils.Base64Utils;
import com.xc.tool.utils.HttpUtils;
import com.xc.tool.utils.JSONUtils;
import com.xc.tool.utils.Md5Utils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.nio.charset.Charset;
import java.util.Map;
import java.util.TreeMap;

/**
 * <p>上传文件rest接口</p>
 *
 * @author xc
 * @version v1.0.0
 */
@RestController
@Api(tags = "上传文件rest接口")
public class UploadRest {

    @Autowired
    private UploadService uploadService;
    @Autowired
    private Constants constants;
    @Autowired
    private FolderService folderService;

    @ApiOperation(value = "创建当前用户的文件",
            notes = "1，单次上传，传入的size和文件的size必须相等\n" +
                    "2，分段上传，首次请求fileIndex必须等于零，根据返回的renewalSize确定每次上传多少\n")
    @ApiImplicitParams({
            @ApiImplicitParam(value = "用户token", name = "token", paramType = "header", required = true),
            @ApiImplicitParam(value = "文件数据", name = "file", paramType = "body", required = true),
    })
    @PostMapping("/current_user/file")
    @Authority
    public UploadDto createCurrentUserFile(TokenModel tokenModel, UploadBean uploadBean, MultipartFile file) {
        UploadDto uploadDto = createFile(tokenModel.getUserId(), uploadBean, file);
        if (uploadDto.getUploadUrl() != null) {
            uploadDto.setUploadUrl(uploadDto.getUploadUrl() + "/current_user/file");
        } else {
            uploadDto.setUploadUrl(constants.getLocalUrl() + "/current_user/file");
        }
        return uploadDto;
    }


    @ApiOperation(value = "创建应用的文件,文件储存在该用户的网盘目录下",
            notes = "1，单次上传，传入的size和文件的size必须相等\n" +
                    "2，分段上传，首次请求fileIndex必须等于零，根据返回的renewalSize确定每次上传多少\n" +
                    "3，md5签名顺序appId，folderNames，randomStr，timeStamp")
    @ApiImplicitParams({
            @ApiImplicitParam(value = "文件数据", name = "file", paramType = "body", required = true),
    })
    @PostMapping("/app/{appId}/file")
    public UploadDto createAppFile(@PathVariable String appId, UploadBean uploadBean, MultipartFile file) {
        uploadBean.setFolderId(constants.getRootFolder());
        AppDto appDto = RedisUtils.get(uploadBean.getHashCode());
        if (appDto == null) {
            //签名
            Map<String, Object> signMap = new TreeMap<>();
            signMap.put("appId", appId);
            signMap.put("folderPath", uploadBean.getFolderPath());
            signMap.put("randomStr", uploadBean.getRandomStr());
            signMap.put("timeStamp", uploadBean.getTimeStamp());
            String json = JSONUtils.getStringByObject(signMap);
            // 获取token
            String url = constants.getVerifySignUrl() + "" + "?appId=" + appId + "&sign=" + uploadBean.getSign() + "&signData=" + Base64Utils.encodeToString(json.getBytes(Charset.forName("utf-8")));
            HttpResult<AppDto> httpResult = HttpUtils.get(url, AppDto.class);
            if (httpResult.getCode() != 200) {
                ResultException resultException = JSONUtils.getObjectByString(httpResult.getMessage(), ResultException.class);
                throw new OperateException(resultException.getCode(), resultException.getMessage());
            }
            appDto = httpResult.getData();
            RedisUtils.set(uploadBean.getHashCode(), appDto, RedisTime.UPLOAD_APP_INFO.getTime());
        }
        UploadDto uploadDto = createFile(appDto.getUserId(), uploadBean, file);
        if (uploadDto.getUploadUrl() != null) {
            uploadDto.setUploadUrl(uploadDto.getUploadUrl() + "/app/" + appId + "/file");
        } else {
            uploadDto.setUploadUrl(constants.getLocalUrl() + "/app/" + appId + "/file");
        }
        return uploadDto;
    }


    /**
     * 获取签名文件上传
     *
     * @return 签名信息
     */
    @ApiOperation(value = "获取签名文件上传")
    @GetMapping("/sign/file")
    public SignDto getSign() {
        String appId = constants.getAppId();
        String appSecret = "";
        String randomStr = "123456";
        String folderPath = "/root/dev/article";
        String timeStamp = Long.toString(System.currentTimeMillis());
        Map<String, Object> signMap = new TreeMap<>();
        signMap.put("appId", appId);
        signMap.put("folderPath", folderPath);
        signMap.put("randomStr", randomStr);
        signMap.put("timeStamp", timeStamp);
        String json = JSONUtils.getStringByObject(signMap);
        String sign = Md5Utils.getSaltMd5(json, appSecret);
        SignDto signDto = new SignDto();
        signDto.setAppId(appId);
        signDto.setSign(sign);
        signDto.setFolderPath(folderPath);
        signDto.setRandomStr(randomStr);
        signDto.setTimeStamp(timeStamp);
        return signDto;
    }

    /**
     * 创建文件
     *
     * @param userId     用户id
     * @param uploadBean 上传信息
     * @return 上传信息
     */
    private UploadDto createFile(String userId, UploadBean uploadBean, MultipartFile file) {
        if (file == null) {
            throw FailCode.FILE_NOT_EMPTY.getOperateException();
        }
        //创建目录
        String[] folderPaths = {};
        if (uploadBean.getFolderPath() != null && !"".equals(uploadBean.getFolderPath())) {
            String folderPath = uploadBean.getFolderPath();
            if ("/".equals(folderPath.substring(0, 1))) {
                folderPath = folderPath.substring(1);
            }
            folderPaths = folderPath.split("/");
        }
        String folderId = folderService.createFolder(folderPaths, 0, userId, uploadBean.getFolderId());
        uploadBean.setFolderId(folderId);
        //上传文件
        return uploadService.uploadFile(userId, uploadBean, file);
    }
}
